<template>
  <!-- 导入文件(表格文件) -->
  <a-form :form="form" :label-col="{ span: 3 }" class="form-section">
    <!-- 导入文件 -->
    <a-form-item
      label="导入文件"
      :label-col="{ span: 3 }"
      :label-align="'left'"
    >
      <div class="form-item-container">
        <!-- 上传文件按钮 -->
        <a-upload
          :custom-request="uploadDataset"
          accept=".csv,.xlsx,.xls"
          :file-list="fileList"
          class="data-upload-button"
          :before-upload="beforeUpload"
          @change="handleUpload"
        >
          <a-button style="width: 200px;">
            <a-icon-font type="iconshujuguanli-daorushuju" />
            <span style="margin-left: 7px;">选择文件</span>
          </a-button>
        </a-upload>
        <!-- 已上传文件 -->
        <uploaded-file-name
          v-if="fileList.length !== 0"
          :file-name="fileList[0].name"
          :max-width="200"
          @delete="deleteFile"
        />
        <!-- 进度条 -->
        <div v-if="fileList.length !== 0" class="progress-loading">
          <a-progress
            style="flex: 1;"
            :percent="loadingProgress"
            :status="uploadingState"
            :show-info="true"
          />
          <div
            class="loading-text"
            :style="{
              color: uploadingState === 'success' ? '#53c41c' : '#5c5c5c',
            }"
          >
            {{ loadingText }}
          </div>
        </div>
      </div>
    </a-form-item>
    <!-- 文件编码 -->
    <a-form-item
      label="文件编码"
      :label-col="{ span: 3 }"
      :label-align="'left'"
      required
      :rules="[{ required: true, message: '请选择编码!' }]"
    >
      <a-select
        v-decorator="[
          'fileCodingType',
          {
            initialValue: 'utf-8',
          },
        ]"
        placeholder="请选择"
        class="select-box"
        size="small"
        style="width: 316px;"
        :disabled="isUploading"
        @change="codingTypeChanged"
      >
        <a-select-option
          v-for="codingType in datasetCodingType"
          :key="codingType"
          :value="codingType"
          >{{ codingType }}
        </a-select-option>
      </a-select>
    </a-form-item>
    <!-- 选择分类 -->
    <a-form-item
      label="选择文件夹"
      :label-col="{ span: 8 }"
      :label-align="'left'"
      required
      :rules="[{ required: true, message: '请选文件夹!' }]"
    >
      <a-select
        v-decorator="[
          'categoryId',
          {
            rules: [{ required: true, message: '请选择文件夹!' }],
            initialValue: selectedCategoryId,
          },
        ]"
        placeholder="请选择"
        class="select-box"
        size="small"
        style="width: 316px;"
        @change="selectedCategoryIdChanged"
      >
        <a-select-option
          v-for="category in categorySelectOptions"
          :key="category.categoryId"
          :value="category.categoryId"
          >{{ category.categoryName }}
        </a-select-option>
      </a-select>
    </a-form-item>
    <!-- 数据集名称 -->
    <a-form-item
      id="datasetName"
      label="数据集名称"
      :label-col="{ span: 3 }"
      :label-align="'left'"
      class="form-item-content-width-320"
    >
      <a-input
        v-decorator="[
          'datasetName',
          {
            rules: [
              { required: true, message: '请输入数据集名称!' },
              {
                validator: (rule, value, callback) => {
                  if (value.includes(' ')) {
                    callback('数据表名不允许含有空格!')
                    return false
                  }
                  return true
                },
              },
            ],
            validateTrigger: ['blur', 'change'],
            initialValue: datasetName,
          },
        ]"
        :max-length="50"
        class="name-input"
        size="small"
        style="width: 316px;"
        @change="changeDatabaseName"
      >
        <a-icon
          v-show="datasetName.length > 0"
          slot="suffix"
          type="close-circle"
          style="cursor: pointer;"
          @mousedown="clearDatasetName"
        />
      </a-input>
    </a-form-item>
    <!-- 首行作为数据表列字段名称 -->
    <a-form-item
      label=" "
      :label-col="{ span: 3 }"
      :label-align="'left'"
      :colon="false"
    >
      <span style="margin-left: 2px; width: 440px;">
        <a-checkbox
          :checked="firstLineAsFields"
          style="margin-right: 0;"
          :disabled="isUploading"
          @click="changeFirstLine"
        >
          将第一行作为数据表的列字段名称
        </a-checkbox>
      </span>
    </a-form-item>
    <!-- 提示 -->
    <a-form-item :label-col="{ span: 0 }" :label-align="'left'">
      <div class="upload-tips">
        提示：如更改表头信息，请点击数据表头名称进行编辑
      </div>
    </a-form-item>
  </a-form>
</template>

<script lang="ts">
/**
 * modal of table file (表格)
 * @author Jinhui Hou
 */
import { Component } from 'vue-property-decorator'
import UploadDataMixin from '@/components/data/basic-information/upload-data-mixin'
import DataStore from '@/store/modules/data'
import DataUploadStore from '@/store/modules/data-upload'
import UploadedFileName from '@/components/data/particle-component/UploadedFileName.vue'
import { cloneDeep } from 'lodash'
import UserGuideStore from '@/store/modules/user-guide'

interface KeyValue {
  [key: string]: any
}

@Component({
  components: {
    UploadedFileName,
  },
})
export default class TableDataForm extends UploadDataMixin {
  public form: any // form table表单
  private fileName: string = '' // 文件名称
  private fileMd5: string = ''
  public formData: any = null // 上传文件 window.FormData()
  private datasetName: string = '' // 数据集名称
  private firstLineAsFields = true // 第一行是否作为字段名
  private isCancel: boolean = true // 是否取消上传,大文件分块上传中取消上传
  // 提交失败结果
  private submitFailResult: any = {}
  private submitFailCount: number = 0
  /**
   * 神奇
   * @param info
   */
  public handleUpload(info: any) {
    this.handleUploadMixin(info)
  }

  // 高级配置
  // 分隔符号
  public get tableSeparate() {
    return DataUploadStore.tableSeparate
  }
  // 引用符号
  public get tableQuote() {
    return DataUploadStore.tableQuote
  }
  // 转义符号
  public get tableEscape() {
    return DataUploadStore.tableEscape
  }

  /**
   * beforeCreate
   */
  public beforeCreate() {
    this.form = this.$form.createForm(this, { name: 'table_form' })
  }

  // 上传文件数据
  public get datasetData(): any {
    return DataUploadStore.datasetData
  }

  /**
   * 编码方式改变
   * 编码方式改变也要重新上传文件
   */
  public async codingTypeChanged(data: string) {
    this.fileCodingType = data
    // 当已经选择文件后
    if (this.fileList.length > 0) {
      const fileOption: any = {
        file: this.fileList[0].originFileObj,
        filename: this.fileName,
      }
      await this.uploadDataset(fileOption, this.fileMd5)
    }
  }

  /**
   * 修改数据集名称
   * @param $event
   */
  public changeDatabaseName($event: any) {
    this.datasetName = $event.target.value
  }

  /**
   * 清空数据集名称 input
   */
  public clearDatasetName($event?: any) {
    $event?.preventDefault()
    this.form.setFieldsValue({ datasetName: '' })
    this.datasetName = ''
    const target: any = this.$refs.datasetName as HTMLElement
    target?.querySelectorAll('input')[0].focus()
  }

  /**
   * toggle 将第一行作为数据表的列字段名称
   * @private
   */
  private async changeFirstLine() {
    // 修改后需要重新上传
    this.firstLineAsFields = !this.firstLineAsFields
    if (this.fileList?.length > 0) {
      const fileOption: any = {
        file: this.fileList[0].originFileObj,
        filename: this.fileName,
      }
      await this.uploadDataset(fileOption)
    }
    if (this.datasetData?.length > 0) {
      DataUploadStore.setActiveTableFileName(this.datasetData[0].fileName)
    }
  }

  /**
   * 选择文件上传文件 / 修改编码 / 修改是否使用首行做表头都需要上传文件 获取预览数据
   */
  public async uploadDataset(option: any, md5: string = '') {
    // 获取 文件名 和 文件类型
    ;[this.fileName, this.fileType] = option.file.name.toString().split('.')
    this.formData = new window.FormData()
    this.formData.append('filename', option.file.name)
    this.formData.append('charSet', this.fileCodingType)
    this.formData.append('separate', this.tableSeparate)
    this.formData.append('quote', this.tableQuote)
    this.formData.append('escape', this.tableEscape)
    this.formData.append('firstLineAsFields', String(this.firstLineAsFields)) // 第一行是否作为数据表的列字段名称
    // String(this.firstLineAsFields) boolean类型的参数不能赋值给string | Blob类型的参数。
    this.isCancel = false
    this.isUploading = true // 正在上传 状态
    try {
      // 只有 csv 需要分块上传
      if (this.fileType === 'csv') {
        await this.csvFileUpdate(option, md5)
        DataUploadStore.setAdvancedSettingsCollapsePanelShow(true) // 展开高级设置
      } else {
        DataUploadStore.setAdvancedSettingsCollapsePanelShow(false) // 关闭高级设置，避免选择csv后， 不清除文件直接再次选择 excel 文件
        // excel 文件和不需要分块上传
        DataUploadStore.setSpinningMessage('导入中')
        DataUploadStore.setSpinning(true)
        this.formData.append('file', option.file)
        await this.uploadFile(this.formData, option)
        if (this.fileType === 'xls' || this.fileType === 'xlsx') {
          this.fileUpLoadEnd(option)
        }
      }
    } catch (error) {
      console.log(error)
    }
  }

  /**
   * csv 文件上传（大文件需要切片）
   */
  public async csvFileUpdate(option: any, md5: string = '') {
    this.loadingProgress = 0 // 进度
    this.uploadingState = 'active' // 状态
    this.loadingText = '导入中' // 文案
    const chunkSize = 5242880 // 5MB
    const totalChunks: number = Math.ceil(option.file.size / chunkSize) // 块数
    if (md5 === '') {
      this.fileMd5 = (await this.scanningFile(option.file)) as string // 扫描文件计算文件MD5值
    } else {
      // 如果是传入了非空的md5值，则说明是在文件编码类型切换调用的，所以直接上传就好了
      this.fileMd5 = md5
      this.loadingText = '扫描完成'
      this.uploadingState = 'success'
    }
    this.formData.append('totalChunks', totalChunks) // 块数
    this.formData.append('identifier', this.fileMd5)

    // 如果只剩一块则直接上传
    if (totalChunks <= 1) {
      await this.lastFileBlockUpload(option)
    } else {
      await this.notLastFileBlockUpload(option, totalChunks)
    }
  }

  /**
   * 扫描文件并计算 MD5 值
   */
  public scanningFile(file: any) {
    return new Promise((resolve, reject) => {
      this.loadingProgress = 0
      this.uploadingState = 'active'
      this.loadingText = '扫描中'
      const SparkMD5 = require('spark-md5') // 计算文件md5值
      const blobSlice = File.prototype.slice
      const chunkSize = 5242880 // 5MB
      const chunks = Math.ceil(file.size / chunkSize)
      const spark = new SparkMD5.ArrayBuffer()
      const fileReader = new FileReader()
      let currentChunk = 0
      const loadNext = () => {
        const start = currentChunk * chunkSize
        const end =
          start + chunkSize >= file.size ? file.size : start + chunkSize
        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end))
      }
      fileReader.addEventListener('load', (event: any) => {
        spark.append(event.target.result) // Append array buffer
        currentChunk += 1
        // 如果中途取消了
        if (this.isCancel) {
          reject()
        }
        this.loadingProgress = Math.floor((100 * currentChunk) / chunks)
        if (currentChunk < chunks) {
          loadNext()
        } else {
          const md5: string = spark.end() // 得到md5
          spark.destroy() // 释放缓存
          this.loadingText = '扫描完成'
          this.uploadingState = 'active'
          resolve(md5)
        }
      })
      fileReader.addEventListener('error', () => {
        file.cancel()
        this.loadingText = '扫描失败'
        this.uploadingState = 'exception'
      })
      loadNext()
    })
  }

  /**
   * 最后一块文件块上传
   */
  public async lastFileBlockUpload(option: any) {
    this.loadingProgress = 100
    this.formData.append('file', option.file)
    this.formData.set('chunkNumber', '0')
    await this.uploadFile(this.formData, option)
    this.isCancel = false
    this.isUploading = false
  }

  /**
   * 不是最后一块文件切片上传
   * @param option
   * @param totalChunks 块数
   */
  public async notLastFileBlockUpload(option: any, totalChunks: number) {
    // 检查文件md5值
    const response = await DataUploadStore.checkFileMd5(this.formData)
    if (response.data.code === 100) {
      const { result } = response.data
      const { code, data, missChunks } = result
      if (code === 200) {
        // 文件已经存在
        DataUploadStore.setDatasetData(data)
        this.loadingProgress = 100
        this.fileUpLoadEnd(option)
      } else if (code === 206) {
        // 文件上传了一部分
        // 先获取已经上传过的文件块的处理进度
        const checkProgress = await this.checkUploadedChunksProgress(
          this.formData,
          totalChunks
        )
        this.loadingProgress = Math.floor(
          (100 * (totalChunks - missChunks.length)) / totalChunks
        )
        // 判断 code 是 200 还是 206
        if (checkProgress.code === 200) {
          DataUploadStore.setDatasetData(checkProgress.data)
          this.loadingProgress = 100
          this.fileUpLoadEnd(option)
        } else if (checkProgress.code === 206) {
          // 开始上传未上传的文件块
          await this.uploadChunkFile(
            option.file,
            this.formData,
            option,
            missChunks
          )
        } else if (code === 405) {
          this.$message.warning('该环节出现错误，请重复执行')
        }
      } else if (code === 404) {
        // 文件没有上传过
        const allChunks = []
        for (let i = 0; i < totalChunks; i += 1) {
          allChunks.push(i)
        }
        await this.uploadChunkFile(
          option.file,
          this.formData,
          option,
          allChunks
        )
      } else if (code === 405) {
        this.$message.warning('该环节出现错误，请重复执行')
      }
    }
    // 如果没有请求成功，则打印报错信息
    else if (response.data.tips) {
      this.$message.warning(response.data.tips)
    } else {
      this.$message.warning(response.data.message)
    }
    this.isUploading = false
  }

  /**
   * 获取已经上传的文件块的处理进度
   */
  public async checkUploadedChunksProgress(formData: any, totalChunks: number) {
    this.uploadingState = 'active'
    this.loadingText = '校验中'
    // 每隔 time delay 毫秒发送一次请求
    const checkProgressInInterval = (timeDelay: number) => {
      return new Promise((resolve) => {
        setTimeout(async () => {
          const response = await DataUploadStore.checkProgress(formData)
          if (response.data.code === 100) {
            const { result } = response.data
            const { code, progress, data } = result
            // 如果 progress 和 result 都为空，则还没开始处理，如果progress为空，result不为空，则表示上传结束
            if (progress === null) {
              resolve({ code, data, success: true })
            } else {
              this.loadingProgress = Math.floor((100 * progress) / totalChunks)
              resolve({ code, data, success: false })
            }
          }
        }, timeDelay)
      })
    }
    // eslint-disable-next-line no-constant-condition
    while (true) {
      if (this.isCancel) {
        throw new Error('file upload cancel')
      }
      try {
        // eslint-disable-next-line no-await-in-loop
        const { code, data, success }: any = await checkProgressInInterval(500)
        if (success) {
          return { code, data }
        }
      } catch (error) {
        throw new Error(error)
      }
    }
  }

  /**
   * csv和excel文件上传完毕
   */
  public fileUpLoadEnd(option: any) {
    // data upload success, user guide to the next step
    UserGuideStore.toSpecifiedGuideStep(4)
    this.form.setFieldsValue({ datasetName: this.fileName })
    this.datasetName = this.fileName
    // this.$refs.datasetName.querySelectorAll('input')[0].focus()  // 数据集名称 聚焦
    const data: any = this.datasetData.map((item: any) => {
      return {
        ...item,
        newHead: item.head,
      }
    })
    // 增加了 newHead
    DataUploadStore.setDatasetData(data)
    // 预览数据
    if (this.datasetData.length > 0) {
      DataUploadStore.setPreviewedDatasetOfTable(cloneDeep(this.datasetData)) // 预览数据
      DataUploadStore.setDataInformationCollapsePanelShow(true) // 显示数据信息 collapsePanel
    }
    // 上传完成 初始化 导入设置 是否导入 是否脱敏等 供配置弹窗使用
    this.initDesensitizationList(this.datasetData) // 脱敏配置
    DataUploadStore.setActiveTableFileName(this.datasetData[0].fileName) // 预览的表明 （上传 excel 可能会有多个 sheet 表）
    // 通过 form 组件调用
    if (option.onSuccess) {
      option.onSuccess()
    }
    this.loadingText = '导入完成'
    this.loadingProgress = 100
    this.uploadingState = 'success'
    this.isCancel = false
    this.isUploading = false
  }

  /**
   * 上传分块文件
   * 首先上传第一块文件，用于检查文件表头信息
   * 如果第一块文件上传成功，则分10个块为1组，同步上传
   * 都上传成功后，再上传最后一个文件
   * @param file
   * @param formData
   * @param option
   * @param missChunks
   */
  public async uploadChunkFile(
    file: any,
    formData: any,
    option: any,
    missChunks: any[]
  ) {
    this.uploadingState = 'active'
    this.loadingText = '导入中'
    let allSuccess: boolean = false // 是否全部导入成功

    const blobSlice = File.prototype.slice
    const chunkSize = 5242880 // 5MB
    const chunks = Math.ceil(file.size / chunkSize)
    let completeChunks = chunks - missChunks.length
    this.loadingProgress = Math.floor((100 * completeChunks) / chunks)

    // 加载分块文件
    const loadChunkFile = (chunkIndex: number) => {
      const start = chunkIndex * chunkSize
      const end = start + chunkSize >= file.size ? file.size : start + chunkSize
      return blobSlice.call(file, start, end)
    }

    formData.append('chunkNumber', 0)
    formData.append('chunkSize', chunkSize)
    formData.append('file', option.file)

    // 临时数组，保存最后渲染的数据
    let temporaryData: any = []

    // 封装请求一组发送
    const requestLists = []
    const firstChunk = missChunks[0]
    let lastChunk = null
    if (missChunks.length > 1) {
      lastChunk = missChunks[missChunks.length - 1]
    }
    missChunks = missChunks.slice(0, -1)
    for (let i = 1; i < missChunks.length; i += 10) {
      requestLists.push(missChunks.slice(i, i + 10))
    }

    // 同时请求
    const requestUploadFileChunks = (requests: number[]) => {
      return new Promise((resolve, reject) => {
        let success: boolean = true
        let passedRequset = 0 // 已经返回的请求数
        // 对每个文件片进行请求
        requests.forEach((chunkIndex: number) => {
          // 隔30ms发送一次，减少服务器压力
          setTimeout(() => {
            const chunkFile = loadChunkFile(chunkIndex)
            formData.set('file', chunkFile)
            formData.set('chunkNumber', chunkIndex.toString())
            DataStore.uploadDatasetFile(formData).then(
              (response: any) => {
                passedRequset += 1
                // 如果中途取消了
                if (this.isCancel) {
                  reject()
                }
                if (response.data.code === 100) {
                  completeChunks += 1
                  this.loadingProgress = Math.floor(
                    (100 * completeChunks) / chunks
                  )
                  // 后端返回上传成功，则获取数据
                  if (response.data.result.complete) {
                    allSuccess = true
                    temporaryData = response.data.result.data // 预览数据
                  }
                } else {
                  success = false
                }
                // 如果当前所有请求完了
                if (passedRequset === requests.length) {
                  resolve(success)
                }
              },
              () => {
                passedRequset += 1
                success = false
              }
            )
          }, 30)
        })
      })
    }
    try {
      // 先上传第一个块，如果第一个请求失败了，就不继续上传了
      const firstSuccess = await requestUploadFileChunks([firstChunk])
      if (firstSuccess) {
        // eslint-disable-next-line no-restricted-syntax
        for (const list of requestLists) {
          // eslint-disable-next-line no-await-in-loop
          await requestUploadFileChunks(list)
        }
        if (lastChunk !== null) {
          // 最后上传最后一个
          await requestUploadFileChunks([lastChunk])
        }
      }
    } catch (error) {
      console.log(error)
      return
    }

    // 所有请求都返回了
    if (allSuccess) {
      DataUploadStore.setDatasetData(temporaryData)
      this.fileUpLoadEnd(option)
    } else {
      this.uploadingState = 'exception'
      this.loadingText = '导入失败'
    }
  }

  /**
   * 上传文件
   */
  public async uploadFile(formData: any, option: any) {
    // 更新默认推断状态
    DataUploadStore.setIsDataTypeInfer(true) // 使用类型推断
    DataUploadStore.setIsDataSemanticInfer(false) // 不实用语义推断
    try {
      // csv excel file upload
      const response = await DataUploadStore.uploadDatasetFile(formData)
      DataUploadStore.setSpinning(false)
      if (response.data.code === 100) {
        const { result } = response.data
        DataUploadStore.setDatasetData(result.data) // 预览数据
      } else {
        DataUploadStore.setDatasetData(null)
        if (response.data.tips) {
          this.$message.warning(response.data.tips)
        } else {
          this.$message.warning(response.data.message)
        }
        return
      }
    } catch (error) {
      DataUploadStore.setSpinning(false)
      this.fileList = []
      DataUploadStore.setDatasetData(null)
      this.$message.error('数据上传失败，请稍后重试')
      this.loadingText = '导入失败'
      this.uploadingState = 'exception'
      console.error(`upload error: ${error}`)
      return
    }
    // 是 csv excel 表格文件上传
    this.fileUpLoadEnd(option)
  }

  /**
   *  删除当前的文件
   */
  public deleteFile() {
    this.isCancel = true
    this.isUploading = false
    this.fileList = []
    this.fileType = ''
    this.form.setFieldsValue({ datasetName: '' }) // 表单的 数据集名称
    this.datasetName = ''
    DataUploadStore.initStore()
  }

  /**
   * 初始化 脱敏列表
   * @param tables
   */
  public initDesensitizationList(tables: any) {
    const historyDesensitization: any = cloneDeep(
      DataUploadStore.haveSetDesensitization
    ) // 历史脱敏配置的备份
    DataUploadStore.setHaveSetDesensitization({}) // init
    if (tables) {
      tables.forEach((table: any) => {
        const columnMap: any = {} // 每张表对应的脱敏配置
        table.head.forEach((column: any) => {
          const columnKey: string =
            typeof column === 'string' ? column : column.name
          let columnHistory: any = {}
          if (
            historyDesensitization &&
            historyDesensitization[table.name] &&
            historyDesensitization[table.name][columnKey]
          ) {
            columnHistory = historyDesensitization[table.name][columnKey] // 历史配置信息
          }
          columnMap[columnKey] = {
            dataLevelId: 1,
            dataMaskingType: 'md5',
            importColumn: true,
            masking: false,
            ...columnHistory,
          }
        })
        DataUploadStore.setHaveSetDesensitizationContent({
          [table.name]: columnMap,
        })
      })
    } else {
      DataUploadStore.setHaveSetDesensitization({})
    }
  }

  // 脱敏配置
  public get haveSetDesensitization() {
    return DataUploadStore.haveSetDesensitization
  }
  // 数据预览当前激活的表
  public get activeTableFileName() {
    return DataUploadStore.activeTableFileName
  }
  // 预览数据
  public get previewedDatasetOfTable() {
    return DataUploadStore.previewedDatasetOfTable
  }

  /**
   * DataUploadIndex 父组件调用， 取消上传
   * 必须方法
   */
  public cancelImportData() {
    this.fileName = '' // 文件名称
    this.fileMd5 = ''
    this.datasetName = '' // 数据集名称
    // 提交失败结果
    this.submitFailResult = {}
    this.submitFailCount = 0

    this.uploadingState = 'active' // 加载状态
    this.loadingProgress = 0 // 加载进度
    this.loadingText = '导入中' // 加载文本

    this.isUploading = false
    this.fileList = []
    this.fileType = '' // 数据类型
    this.form.setFieldsValue({ datasetName: '' }) // 表单的 数据集名称
    DataUploadStore.initStore()
  }

  /**
   * 高级配置更改触发事件（修改其他配置后重新上传文件）
   */
  public advancedSettingTriggeringEvent() {
    this.codingTypeChanged(this.fileCodingType) // 借用编码方式改变进行重新上传
  }

  /**
   * 处理上传文件的数据
   * 参数：
   *   文件分类，文件类型，文件名称，导入配置（语义， 类型）...
   * 是否导入 脱敏 (use methods: handleSubmit )
   */
  public dealWriteFileData(values: any) {
    const { haveSetDesensitization } = DataUploadStore
    const fileType: string = this.fileList[0].name.slice(
      this.fileList[0].name.lastIndexOf('.') + 1
    )
    return {
      categoryId: values.categoryId, // 选择文件分类
      importType: fileType.includes('csv') ? 'csv' : 'excel', // 文件类型
      name: values.datasetName, // 文件名称
      files: this.datasetData.map((item: any) => {
        return {
          filename: item.fileName, // 每一张表（例如 excel 可以有多张 sheet）
          firstLineAsFields: this.firstLineAsFields, // 将第一行作为数据表的列字段名称
          identifier: this.fileMd5,
          data: item.newHead.map(
            (column: {
              name: string
              type: string
              semantic?: string
              recommendSemantic: string
            }) => {
              // 某张表 某列的配置
              const columnSet = haveSetDesensitization[item.name][column.name]
              return {
                name: column.name,
                type: column.type,
                dataLevelId: columnSet?.masking ? columnSet.dataLevelId : null,
                dataMaskingType: columnSet?.masking
                  ? columnSet.dataMaskingType
                  : null,
                importColumn: columnSet?.importColumn || false,
                semantic: column.semantic ? column.semantic : 'null', // 语义
              }
            }
          ),
          sheetName: item.name,
        }
      }),
      charSet: this.fileCodingType, // 文件编码
      separate: this.tableSeparate, // 分隔符号
      quote: this.tableQuote, // 引用符号
      escape: this.tableEscape, // 转义符号
      firstImport: true,
    }
  }

  /**
   * DataUploadIndex 父组件调用， 确认导入
   */
  public handleSubmit() {
    // 校验
    this.form.validateFields(async (error: Error, values: any) => {
      if (!error) {
        const passData = this.dealWriteFileData(values) // 处理后的 请求参数 加入了 列的是否导入 是否脱敏 等参数
        // 解决空文件上传的问题
        if (
          !(
            passData.files &&
            passData.files[0] &&
            passData.files[0].data &&
            passData.files[0].data.length > 0
          )
        ) {
          this.$message.error('请确保上传文件包含有效数据')
          this.deleteFile()
          return
        }
        DataUploadStore.setSpinningMessage('上传中')
        DataUploadStore.setSpinning(true)
        try {
          const response = await DataUploadStore.writeFinalDataset(passData)
          // 导入数据不成功的话
          if (response.data.code !== 100) {
            DataStore.setMessageModalOption({
              visible: true,
              message: '导入数据失败',
              tips: `原因：${response.data.message}\n提示：${response.data.tips}`,
            })
            // 数据转化类型成功 处理提交失败
            if (response.data.code !== 40013 && this.fileType === 'csv') {
              this.handleSubmitFail(values)
            }
          }
          // 数据导入成功
          if (DataUploadStore.writeDatasetSucceed) {
            await DataStore.loadDatasetCategory() // 更新左侧列表
            // 周宇改后的接口
            const { datasetIds } = response.data.result
            let datasetId: any
            let ids: any[]
            if (!datasetIds) {
              datasetId = response.data.result.datasetId
              ids = [datasetId]
            } else {
              ;[datasetId] = datasetIds
              ids = datasetIds
            }
            DataStore.setSelectedDatasetId(datasetId) // 设置左侧列表查看
            DataUploadStore.cancelImport()
            this.submitFailCount = 0
            this.$message.success('上传成功！')
            await this.goBackPreView(
              'table',
              ids // 多 sheet 表
            )
            this.$emit('form-set-selected-keys', [`dataset${datasetId}`])
            // data upload success, user guide to the next step
            UserGuideStore.toSpecifiedGuideStep(5)
          }
          DataUploadStore.setSpinning(false)
          this.fileType = this.fileList[0].name.slice(
            this.fileList[0].name.lastIndexOf('.') + 1
          )
        } catch (error_) {
          console.error('writeFinalDataset error:', error_)
          DataUploadStore.setSpinning(false)
        }
      } else {
        console.error('error:', error)
        this.fileType = ''
      }
    })
  }

  /**
   * 点击确定提交数据 出现错误的情况
   */
  public handleSubmitFail(values: any) {
    const postData = this.getErrorTableInfo(values)
    const errorResult: any = DataUploadStore.parseErrorFile(postData)
    // 已上传文件信息修改
    this.fileType = ''
    // 呈现错误信息
    errorResult
      .then((result: any) => {
        if (
          result.data.result &&
          result.data.result.errorCount >= 0 &&
          result.data.result.errorLineCodeInfoMap
        ) {
          DataStore.setSubmitFailModalVisible(true)
          this.submitFailResult = result.data.result
        }
      })
      .catch((error: any) => {
        console.log('fail info error', error)
      })
    this.submitFailCount += 1
  }

  /**
   * 获取上传表格信息
   */
  public getErrorTableInfo(value: any) {
    const categoryItem = DataStore.datasetCategory.find((item: any) => {
      return item.categoryName === value.category
    })
    const headData: any[] = []
    this.datasetData[0].head.forEach((head: any) => {
      const item = {
        name: head.name,
        type: head.type,
        semeantic: head.semantic === undefined ? 'null' : head.semantic,
        dataLevelId: null,
        dataMaskingType: null,
        importColumn: true,
      }
      headData.push(item)
    })
    const result: KeyValue = {
      categoryId: categoryItem?.categoryId,
      data: headData,
      filename: this.datasetData[0].fileName.split('_')[0],
      firstLineAsFields: this.firstLineAsFields,
      importType: this.fileList[0].name.split('.')[1],
      name: this.fileName,
      identifier: this.fileMd5,
      sheetName: this.fileName,
      charSet: this.fileCodingType,
      separate: this.tableSeparate,
      quote: this.tableQuote,
      escape: this.tableEscape,
    }
    return result
  }
}
</script>
<style lang="less" scoped>
@import './data-type';
</style>
